﻿using Common.FrontEnd;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Util.Props;

namespace FrontEnd.Transform
{
    /// <summary>
    /// Applies the Lifter to the input mel-cepstrum to 
    /// smooth cepstrum values
    /// 
    /// @author Horia Cucu
    /// </summary>
    public class Lifter:BaseDataProcessor
    {
        /** The property for the value of the lifterValue */
        [S4Integer(defaultValue = 22)]
        public static String PROP_LIFTER_VALUE = "lifterValue";
        protected int lifterValue;

        protected int cepstrumSize; // size of a Cepstrum
        protected double[] lifterWeights;

        public Lifter(int lifterValue) 
        {
            this.lifterValue = lifterValue;
        }

        public Lifter() {
        }

        override
        public void newProperties(PropertySheet ps)
        {
            base.newProperties(ps);
            lifterValue = ps.getInt(PROP_LIFTER_VALUE);
        }

        
        public void initialize() {
            base.initialize();
        }

        /**
        /// Returns the next DoubleData object, which is the lifted mel-cepstrum of
        /// the input mel-cepstrum. Signals are returned unmodified.
        /// 
        /// @return the next available DoubleData lifted mel-cepstrum, or Signal
        ///         object, or null if no Data is available
        /// @throws DataProcessingException
        ///             if a data processing error occurred
         */
        public IData getData()
        {
            IData data = getPredecessor().getData(); // get the cepstrum
            if (data != null && data is DoubleData) {
                liftCepstrum((DoubleData) data);
            }
            return data;
        }

        /**
        /// Lifts the input mel-cepstrum.
        /// 
        /// @param input
        ///            a mel-cepstrum frame
        /// @throws IllegalArgumentException
         */
        private void liftCepstrum(DoubleData input) 
        {
            double[] melCepstrum = input.Values;

            if (lifterWeights == null) {
                cepstrumSize = melCepstrum.Length;
                computeLifterWeights();
            } else if (melCepstrum.Length != cepstrumSize) {
                throw new ArgumentException(
                        "MelCepstrum size is incorrect: "
                                + "melcepstrum.length == " + melCepstrum.Length
                                + ", cepstrumSize == " + cepstrumSize);
            }

            for (int i = 0; i < melCepstrum.Length; i++) {
                melCepstrum[i] = melCepstrum[i]* lifterWeights[i];
            }
        }

        /**
        /// Computes the Lifter weights.
         */
        private void computeLifterWeights() {
            lifterWeights = new double[cepstrumSize];
            for (int i = 0; i < cepstrumSize; i++) {
                lifterWeights[i] = 1 + lifterValue / 2
                       * Math.Sin(i* Math.PI / lifterValue);
            }
        }

    }
}
